package com.parking.mgr.useraccount.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.parking.mgr.common.cache.RedisCache;
import com.parking.mgr.common.constant.CommonConstant;
import com.parking.mgr.common.enums.CommonStatusEnum;
import com.parking.mgr.common.exception.ServiceException;
import com.parking.mgr.common.exception.enums.CommonExceptionEnum;
import com.parking.mgr.common.exception.enums.DeleteUpdateExceptionEnums;
import com.parking.mgr.common.exception.enums.StatusExceptionEnum;
import com.parking.mgr.common.factory.TreeBuildFactory;
import com.parking.mgr.common.util.IdUtils;
import com.parking.mgr.useraccount.model.entity.BasicCodeEntity;
import com.parking.mgr.useraccount.model.mapper.BasicCodeMapper;
import com.parking.mgr.useraccount.model.mapstruct.BasicCodeMapStruct;
import com.parking.mgr.useraccount.model.param.BasicCodeParam;
import com.parking.mgr.useraccount.model.vo.BasicCodeVO;
import com.parking.mgr.useraccount.service.BasicCodeService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName BasicCodeServiceImpl
 * @Description TODO
 * @Auther: shilintao
 * @Date: 2023/5/24
 */
@Service
public class BasicCodeServiceImpl extends ServiceImpl<BasicCodeMapper, BasicCodeEntity> implements BasicCodeService {

    @Resource
    private BasicCodeMapper basicCodeMapper;

    @Resource
    private BasicCodeMapStruct basicCodeMapStruct;

    @Resource
    private RedisCache redisCache;

    @Override
    public List<BasicCodeVO> list(BasicCodeParam basicCodeParam) {
        LambdaQueryWrapper<BasicCodeEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(basicCodeParam)) {
            //根据数据字典名模糊查询
            if (ObjectUtil.isNotEmpty(basicCodeParam.getFName())) {
                queryWrapper.like(BasicCodeEntity::getFName, basicCodeParam.getFName());
            }
        }

        queryWrapper.orderByAsc(BasicCodeEntity::getFSortNumber);
        queryWrapper.orderByAsc(BasicCodeEntity::getFInsertTimeMillis);
//        queryWrapper.eq(BasicCodeEntity::getFKey,basicCodeParam.getFKey());
        List<BasicCodeEntity> basicCodeList = this.list(queryWrapper);

        //将结果集合处理成树
        List<BasicCodeEntity> codeTree = new TreeBuildFactory<BasicCodeEntity>().build(basicCodeList);
        List<BasicCodeVO> codeVOTrees = basicCodeMapStruct.entity2VO(codeTree);
        return codeVOTrees;
    }

    @Override
    public List<BasicCodeVO> listEnable(BasicCodeParam basicCodeParam) {
        LambdaQueryWrapper<BasicCodeEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(basicCodeParam)) {
            //根据数据字典名模糊查询
            if (ObjectUtil.isNotEmpty(basicCodeParam.getFName())) {
                queryWrapper.like(BasicCodeEntity::getFName, basicCodeParam.getFName());
            }
        }

        queryWrapper.eq(BasicCodeEntity::getFEnableState, CommonStatusEnum.ENABLE.getCode());
        queryWrapper.orderByAsc(BasicCodeEntity::getFSortNumber);
        queryWrapper.orderByAsc(BasicCodeEntity::getFInsertTimeMillis);
//        queryWrapper.eq(BasicCodeEntity::getFKey,basicCodeParam.getFKey());
        List<BasicCodeEntity> basicCodeList = this.list(queryWrapper);

        //将结果集合处理成树
        List<BasicCodeEntity> codeTree = new TreeBuildFactory<BasicCodeEntity>().build(basicCodeList);
        List<BasicCodeVO> codeVOTrees = basicCodeMapStruct.entity2VO(codeTree);
        return codeVOTrees;
    }

    @Override
    public void add(BasicCodeParam basicCodeParam) {
        // 桉树校验
        checkParam(basicCodeParam, false);
        BasicCodeEntity basicCodeEntity = new BasicCodeEntity();
        BeanUtil.copyProperties(basicCodeParam, basicCodeEntity);
        String fKeyParam = basicCodeParam.getFKey();
        // UUID生成fKey
        String fKey = IdUtils.getKeyUUID();
        basicCodeEntity.setFKey(fKey);
        basicCodeEntity.setFEnableState(CommonStatusEnum.ENABLE.getCode());
        basicCodeEntity.setId(IdUtils.getId());
        basicCodeEntity.setFSortNumber(basicCodeParam.getFSortNumber() == 0 ? CommonConstant.SORT_NUMBER : basicCodeParam.getFSortNumber());
        this.save(basicCodeEntity);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Collection<String> ids) {
        for (String id : ids) {
            BasicCodeEntity basicCodeEntity = this.basicCodeMapper.selectById(id);
            if (ObjectUtil.isNull(basicCodeEntity)) {
                throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());

            }
            if (ObjectUtil.equals(CommonConstant.CAN_DELETE, basicCodeEntity.getFCanDelete())) {
                Set<String> childList = this.getChildIdListById(Collections.singletonList(id));
                if (childList.isEmpty()) {
                    this.removeById(id);
                } else {
                    throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_DELETE_EXIST_CHILD_NODE.getMessage());
                }
            } else {
                throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_DELETE.getMessage());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BasicCodeParam basicCodeParam) {
        // 参数校验
        checkParam(basicCodeParam, true);
        // 获取修改的数据字典旧数据
        BasicCodeEntity basicCodeEntity = this.basicCodeMapper.selectById(basicCodeParam.getId());
        if (ObjectUtil.isNull(basicCodeEntity)) {
            throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());

        }
//        BasicCodeEntity currentCode = this.queryBasicCode(basicCodeParam);
        if (ObjectUtil.equals(CommonConstant.CAN_UPDATE, basicCodeEntity.getFCanUpdate())) {
            BeanUtil.copyProperties(basicCodeParam, basicCodeEntity);
            basicCodeMapper.updateById(basicCodeEntity);
        } else {
            throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_UPDATE.getMessage());
        }
    }

    @Override
    public void move(String currentId, String newId) {
        // 获取当前节点的数据字典对象
        BasicCodeEntity currentCode = this.getById(currentId);
        // 获取当前节点所有的子节点
        Set<String> childIdListById = this.getChildIdListById(Collections.singletonList(currentId));
        if (ObjectUtil.isNotEmpty(childIdListById)) {
            if (childIdListById.contains(newId)) {
                throw new ServiceException(CommonExceptionEnum.CAN_NOT_MOVE_CURRENT_NODE.getMessage());
            }
        }
        // 获取当前目录的父节点
        String parentId = currentCode.getFkParentId();
        if (parentId.equals(newId)) {
            throw new ServiceException(CommonExceptionEnum.CAN_NOT_MOVE_CURRENT_NODE.getMessage());
        }
        currentCode.setFkParentId(newId);
        this.updateById(currentCode);
    }

    @Override
    public List<BasicCodeVO> getCodeByFKey(String fKey) {
        String cacheKey = "/basic/code/" + fKey;
        LambdaQueryWrapper<BasicCodeEntity> queryWrapper = new LambdaQueryWrapper<BasicCodeEntity>()
                .eq(BasicCodeEntity::getFKey, fKey);
        queryWrapper.orderByAsc(BasicCodeEntity::getFSortNumber);
        queryWrapper.orderByAsc(BasicCodeEntity::getFInsertTimeMillis);

        List<BasicCodeEntity> listc = CollectionUtil.newArrayList();

        if (redisCache.hasKey(cacheKey)) {
            listc = redisCache.getCacheList(cacheKey);
        } else {
            listc = this.list(queryWrapper);
            redisCache.setCacheList(cacheKey, listc);
            redisCache.expire(cacheKey, CommonConstant.EXPIRE_TIME);
        }

        // 获取当前节点的数据对象
        for (BasicCodeEntity currentCodeEntity : listc) {
            LambdaQueryWrapper<BasicCodeEntity> queryWrapperchild = new LambdaQueryWrapper<BasicCodeEntity>()
                    .eq(BasicCodeEntity::getFkParentId, currentCodeEntity.getId());
            queryWrapperchild.orderByAsc(BasicCodeEntity::getFSortNumber);
            queryWrapperchild.orderByAsc(BasicCodeEntity::getFInsertTimeMillis);
            List<BasicCodeEntity> basicCodeList = this.list(queryWrapperchild);
            // 将结果集构造成树
            List<BasicCodeEntity> codeTree = new TreeBuildFactory<BasicCodeEntity>().buildChild(currentCodeEntity.getId(), basicCodeList);
            List<BasicCodeVO> codeVOTrees = basicCodeMapStruct.entity2VO(codeTree);
            return codeVOTrees;
        }
        List<BasicCodeEntity> codeTree = new TreeBuildFactory<BasicCodeEntity>().build(listc);
        List<BasicCodeVO> codeVONullTrees = basicCodeMapStruct.entity2VO(codeTree);
        return codeVONullTrees;
    }

    @Override
    public boolean isUniqueKey(String id, String key) {
        LambdaQueryWrapper<BasicCodeEntity> queryWrapper = new LambdaQueryWrapper<BasicCodeEntity>().eq(BasicCodeEntity::getFKey, key);
        BasicCodeEntity basicCodeEntity = basicCodeMapper.selectOne(queryWrapper);
        if (ObjectUtil.isNotNull(basicCodeEntity)) {
            String dataId = basicCodeEntity.getId();
            if (!StrUtil.equals(id, dataId)) {
                throw new ServiceException(StatusExceptionEnum.IS_NOT_UNIQUE_KEY.getMessage());
            }
        }
        return true;
    }

    /**
     * 获取数据字典数据
     *
     * @param basicCodeParam
     * @return
     */
    private BasicCodeEntity queryBasicCode(BasicCodeParam basicCodeParam) {
        BasicCodeEntity basicCodeEntity = this.getById(basicCodeParam.getId());
        if (ObjectUtil.isNull(basicCodeEntity)) {
            throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());
        }
        return basicCodeEntity;
    }


    /**
     * 参数校验
     */
    private void checkParam(BasicCodeParam basicCodeParam, boolean isExcludeSelf) {
        //编辑时，parentId和id不能一致，一致会导致无限递归
        if (isExcludeSelf) {
            if (basicCodeParam.getId().equals(basicCodeParam.getFkParentId())) {
                throw new ServiceException(CommonExceptionEnum.PARENT_ID_CAN_NOT_EQ_CURRENT_ID.getMessage());
            }
            //编辑时，父id不能为自己的字节点
            Set<String> childIdListById = this.getChildIdListById(Collections.singletonList(basicCodeParam.getId()));
            if (ObjectUtil.isNotEmpty(childIdListById)) {
                if (childIdListById.contains(basicCodeParam.getFkParentId())) {
                    throw new ServiceException(CommonExceptionEnum.PARENT_ID_CAN_NOT_EQ_CHILD_ID.getMessage());
                }
            }
        }
        String id = basicCodeParam.getId();
        String key = basicCodeParam.getFKey();

        LambdaQueryWrapper<BasicCodeEntity> queryWrapperByKey = new LambdaQueryWrapper<>();
        queryWrapperByKey.eq(BasicCodeEntity::getFKey, key).
                ne(BasicCodeEntity::getFEnableState, CommonStatusEnum.DISABLE.getCode());
        if (isExcludeSelf) {
            queryWrapperByKey.ne(BasicCodeEntity::getId, id);
        }
        long countByKey = this.count(queryWrapperByKey);
        if (countByKey >= 1L) {
            throw new ServiceException(CommonExceptionEnum.DATA_REPEAT.getMessage());
        }
    }


    private Set<String> getChildIdListById(Collection<String> parentIds) {
        Set<String> acids = new HashSet<>();
        Collection<String> dpids = parentIds;
        do {
            Set<String> cids = this.list(new LambdaQueryWrapper<BasicCodeEntity>().
                            in(BasicCodeEntity::getFkParentId, dpids)).
                    stream().map(BasicCodeEntity::getId)
                    .collect(Collectors.toSet());
            if (cids.isEmpty()) {
                return acids;
            }
            acids.addAll(cids);
            dpids = cids;
        } while (true);
    }

    /**
     * 根据当前id获取所有的子节点id
     * @param parentIds
     * @return
     */
    /*private Set<String> getChildIdListById(Collection<String> parentIds){
        Set<String> acids = new HashSet<>();
        Collection<String> dpids = parentIds;
        do {
            Set<String> cids = this.list(new LambdaQueryWrapper<BasicCodeEntity>().
                    in(BasicCodeEntity::getFkParentId,dpids))
                    .stream().map(BasicCodeEntity::getId)
                    .collect(Collectors.toSet());
            if (cids.isEmpty()){
                return cids;
            }
            acids.addAll(acids);
            dpids = cids;
        }while (true);
    }*/


}
